<template>
  <div class="wrap">
    <template>
      <div class="section-row tw-justify-evenly">
        <el-radio v-model="sideValue" label="0">{{ $t('message.WingTwistDesignDlg.leftSideWing') }}</el-radio>
        <el-radio v-model="sideValue" label="1">{{ $t('message.WingTwistDesignDlg.RightSideWing') }}</el-radio>
      </div>
      <!--        后掠角-->
      <div class="d-flex align-items-center">
        <label class="label-style">{{$t('message.WingTwistDesignDlg.dlgBackSweepAngle')}}：</label>
        <el-input id="backSweepAngle"
                  v-model="params.backSweepAngle"
                  type = "number"
                  step = "1"
                  :max = this.backSweepAngleMax
                  :min=this.backSweepAngleMin
                  @focus="focus('backSweepAngle')"
                  @change="changeValue('backSweepAngle')"/>
        <label class="label">°</label>
      </div>
<!--      基准面-->
      <div class="d-flex align-items-center">
        <label class="label-style">{{$t('message.WingTwistDesignDlg.datumPlane')}}：</label>
        <query-list
                v-model="params.datumPlane"
                :description="$t('message.WingTwistDesignDlg.datumPlane')"
                :active="params.queryListActiveMap.datumPlane"
                @switchQuery="switchQuery('datumPlane')"
                :tipMsg="$t('message.WingTwistDesignDlg.datumPlane')">
        </query-list>
      </div>

      <!--      各个翼型截面的参数     -->
<!--        @click="clickGroupsItem(group)"-->
<!--        @contextmenu.prevent="ctxClick(group, $event)"-->
      <div>
        <div class="operation-border" >
          <div>
            <label class="label-style">{{ $t('message.WingTwistDesignDlg.sectionList') }}</label>
          </div>
          <el-table ref="sectionList"
                    :data="params.allSectionsInfo"
                    highlight-current-row
                    @current-change="handleCurrentChange"
                    tooltip-effect="dark"
                    style="width: 100%;margin-top: 5px"
                    border size="small">
            <el-table-column prop="index"
                             min-width="25">
              <template v-slot="scope">
                <label class="label">{{scope.row.index + 1}}</label>
              </template>
            </el-table-column>
            <el-table-column prop="sectionPos"
                             :label="$t('message.WingTwistDesignDlg.dlgTextSectionPos')"
                             min-width="100">
              <template v-slot="scope">
                <label class="label">{{ scope.row.sectionPos }}</label>
              </template>
            </el-table-column>
            <el-table-column prop="zoomRatio"
                             :label="$t('message.WingTwistDesignDlg.dlgTextZoomRatio')"
                             min-width="80">
              <template v-slot="scope">
                <label class="label">{{ scope.row.zoomRatio }}</label>
              </template>
            </el-table-column>
            <el-table-column prop="torsionAngle"
                             :label="$t('message.WingTwistDesignDlg.dlgTextTorsionAngle')"
                             min-width="80">
              <template v-slot="scope">
                <label class="label">{{ scope.row.torsionAngle }}</label>
              </template>
            </el-table-column>
            <el-table-column prop="sectionData"
                             :label="$t('message.WingTwistDesignDlg.sectionData')"
                             min-width="80">
              <template v-slot="scope">
<!--                <label class="label">{{ scope.row.sketches }}</label>-->
                <el-button type="text" size="small" @click="viewContent(scope)">
                  {{ $t('message.WingTwistDesignDlg.view') }}
                </el-button>
              </template>
            </el-table-column>
          </el-table>
          <div class="button-style">
            <!--          <label class="el-form-item__label">分组</label>-->
            <el-button type="primary" size="small" :disabled="false" @click="addSectionData()">
              {{ $t('message.WingTwistDesignDlg.addGroup') }}
            </el-button>
            <el-button type="primary" size="small" :disabled="buttonDisabled()" @click="editSectionData()">
              {{ $t('message.WingTwistDesignDlg.edit') }}
            </el-button>
            <el-button type="primary" size="small" :disabled="buttonDisabled()" @click="deleteSectionData()">
              {{ $t('message.WingTwistDesignDlg.deleteGroup') }}
            </el-button>
          </div>
        </div>
      </div>
      <!--        翼型形状-->
      <form ref="form">
        <input type="file" id="file" style="display:none" accept=".txt"/>
      </form>
      <div class="operation-border" v-if="isEdit">
        <div>
          <label class="label-style">{{$t('message.WingTwistDesignDlg.dlgTextWingSection')}}：</label>
          <el-radio v-model="sectionType" label="0" @change="setSectionType">{{ $t('message.WingTwistDesignDlg.importFile') }}</el-radio>
          <el-radio v-model="sectionType" label="1" @change="setSectionType">{{ $t('message.WingTwistDesignDlg.selectSection') }}</el-radio>
        </div>
        <div class="d-flex align-items-center" v-if="sectionType === '0'">
          <el-button id="importSplinePoint" type="primary" size="mini" @click="selectFile" style="width:100%;margin-top: 5px"
                     @keyup.enter.native="selectFile">
            {{ params.sketches.length > 0 ? params.sketches[0].name : $t('message.WingTwistDesignDlg.import')}}
          </el-button>
        </div>
        <div class="d-flex align-items-center" v-else>
          <query-list
                  v-model="params.sketches"
                  :description="$t('message.WingTwistDesignDlg.dlgTextSelectSection')"
                  :active="params.queryListActiveMap.sketches"
                  @clickItem = "selectItem"
                  @switchQuery="switchQuery('sketches')"
                  :tipMsg="$t('message.WingTwistDesignDlg.dlgTextSelectSection')">
          </query-list>
        </div>
        <!--        截面位置-->
        <div class="d-flex align-items-center">
          <label class="label-style">{{$t('message.WingTwistDesignDlg.dlgTextSectionPos')}}：</label>
          <el-input id="sectionPos"
                    v-model="params.sectionPos"
                    type = "number"
                    step = "1"
                    :min=this.sectionPosMin
                    :max=this.sectionPosMax
                    @focus="focus('sectionPos')"
                    @change="changeValue('sectionPos')"/>
          <label class="label">mm</label>
        </div>
<!--                缩放比-->
        <div class="d-flex align-items-center">
          <label class="label-style">{{$t('message.WingTwistDesignDlg.dlgTextZoomRatio')}}：</label>
          <el-input id="zoomRatio"
                    v-model="params.zoomRatio"
                    type = "number"
                    step = "1"
                    :min = this.zoomRatioMin
                    @focus="focus('zoomRatio')"
                    @change="changeValue('zoomRatio')" />
        </div>
        <!--        扭转角-->
        <div class="d-flex align-items-center">
          <label class="label-style">{{$t('message.WingTwistDesignDlg.dlgTextTorsionAngle')}}：</label>
          <el-input id="torsionAngle"
                    v-model="params.torsionAngle"
                    type = "number"
                    step = "1"
                    :max = this.torsionAngleMax
                    :min=this.torsionAngleMin
                    @focus="focus('torsionAngle')"
                    @change="changeValue('torsionAngle')"/>
          <label class="label">°</label>
        </div>
        <div class="button-style">
          <el-button type="primary" size="small" :disabled="false" @click="saveSectionData()">
            {{ $t('message.WingTwistDesignDlg.save') }}
          </el-button>
        </div>
      </div>
    </template>

    <!--    确认和关闭-->
    <div class="btn">
      <el-button
        type="primary"
        size="small"
        :disabled="confirmDisabled()"
        @click="confirm">
        {{ $t('message.WingTwistDesignDlg.confirm') }}
      </el-button>
      <el-button
        size="small"
        @click="close">
        {{ $t('message.WingTwistDesignDlg.cancel') }}
      </el-button>
    </div>
  </div>
</template>

<script>
import DialogMixin from "../DialogMixin";
import {wingTwistDesignCommand} from "../../../Command/WingTwistDesign/WingTwistDesignCommand";
import {eventBus} from "../../../eventbus/eventbus";
import {ElementType} from "../../../modeling/TypeDefine";
import {element} from "three/nodes";

const unitsMap = {
    "": 1,
    "mm": 1,
    "cm": 10,
    "m": 1000,
  }
export default {
  mixins: [DialogMixin],
  name: 'WingTwistDesignDlg',
  data() {
    return {
      params: {
        guideLines:[],
        //wingArea:10,                          //机翼面积
        //aspectRatio:5,                        //展弦比
        //shootRootRatio:0.3,                   //梢根比
        backSweepAngle:0,                     //后掠角

        index: 0,
        name: '1',
        sectionPos: 0,                        //当前截面位置
        zoomRatio: 1,                         //当前截面缩放比
        torsionAngle: 0,                      //当前截面扭转角
        sketches:[],

        //截面组内容
        allSectionsInfo:[
          // {
          //   index: 0,
          //   name: '1',
          //   sectionPos: 0,
          //   zoomRatio: 1,
          //   torsionAngle: 0,
          //   sketches:[],
          // }
        ],

        datumPlane: [],

        queryListActiveMap: {
          sketches: 0,
          guideLines: 0,
          datumPlane: 1,
        },
      },
      selectRow: null,
      wingAreaMin:1,
      aspectRatioMin:1,
      shootRootRatioMax:1,
      shootRootRatioMin:0.01,
      torsionAngleMax:30,
      torsionAngleMin:-30,
      backSweepAngleMax:60,
      backSweepAngleMin:0,
      sectionPosMin:0,
      sectionPosMax:0,
      zoomRatioMax:1000,
      zoomRatioMin:0.001,
      wingSpan:1000,
      selectedItem:null,
      dirWingTip:new THREE.Vector3(0,0,0),       //机翼延伸前进方向，翼根向翼梢方向
      sketchesInfo:[],                                    //草图的信息
      //isRecount:true,                                    //是否需要重新进行点列数据计算，如果是进行重排序、删除操作需要对所有数据进行重算，否则不需要重算提高计算效率
      firstSketch:null,                                   //第一个翼型草图，基准草图
      guideLinesInfo:[],                                  //放样引导线的信息
      reverse:false,                                      //用于对前进方向及角度增加方向进行翻转
      reverseShoot:false,                                 //用于对前进方向及角度增加方向进行翻转
      sideValue:"0",                                        //左侧机翼还是右侧机翼，0左侧，1右侧
      sectionType: "0", //0文件导入，1界面选取
      isEdit: false,
      originValue: 0,//记录输入框修改之前的值
    };
  },
  mounted() {
    wingTwistDesignCommand.init(500,300,500,() => {
      //使用机翼面积、展弦比、梢根比时对翼展的范围限制
      //this.refreshSectionPos();
      wingTwistDesignCommand.setSelectType([ElementType.DATUMPLANE]);
      wingTwistDesignCommand.handlePickElement((data)=> {
        if(this.params.queryListActiveMap.sketches && data.element.length > 0){
          let element = data.element[0].element;
          let entityId = element?.params?.entityRefId;
          let entityName = element?.params?.entityRefName;
          let matrix = element?.params?.entityRefMatrix;
          if (entityId) {
            wingTwistDesignCommand.getElementsByEntityId(entityId, res => {
              //对获取的点进行处理，因翼型变更为上曲线+下曲线方式，为方便计算，在处理时仍采用合并为一条计算，生成时再拆为两条
              let splinesPnts = [];
              let sectionMatrix = this.getSketchMatrix(matrix);
              res.forEach(element => {
                if (element.type === ElementType.CURVE) {
                  let intpPnts = element.params?.intpPnts;
                  splinesPnts.push(intpPnts);
                }
              })
              if (splinesPnts.length === 2) {
                let pnts = [];
                for(let i = splinesPnts[0].length / 3 - 1; i > 0; i--) {
                  let pointVec = new THREE.Vector3(splinesPnts[0][3 * i],splinesPnts[0][3 * i + 1],splinesPnts[0][3 * i + 2]);
                  let point2D = pointVec.clone().applyMatrix4(sectionMatrix.clone().invert());
                  pnts.push(point2D);
                }
                for(let i = 0; i < splinesPnts[1].length / 3; i++) {
                  let pointVec = new THREE.Vector3(splinesPnts[1][3 * i],splinesPnts[1][3 * i + 1],splinesPnts[1][3 * i + 2]);
                  let point2D = pointVec.clone().applyMatrix4(sectionMatrix.clone().invert());
                  pnts.push(point2D);
                }
                if (pnts.length > 0) {
                  //获取草图的矩阵及根据矩阵获取对应的草图信息
                  let sketchSelect = this.createSectionInfo(entityName, matrix, pnts);
                  this.params.sketches = [];
                  this.params.sketches.push(sketchSelect);
                }
                // for(let i = splinesPnts.length / 3 - 1; i >= 0; i--) {
                //   let pointVec = new THREE.Vector3(splinesPnts[3 * i],splinesPnts[3 * i + 1],splinesPnts[3 * i + 2]);
                //   // let point2D = pointVec.clone().applyMatrix4(sectionMatrix.clone().invert());
                //   pnts.push(pointVec);
                // }
                // for(let i = 0; i < splinesPnts.length / 3; i++) {
                //   let pointVec = new THREE.Vector3(splinesPnts[3 * i],splinesPnts[3 * i + 1],splinesPnts[3 * i + 2]);
                //   let point2D = pointVec.clone().applyMatrix4(sectionMatrix.clone().invert());
                //   pnts.push(pointVec);
                // }
              }
            });
          }

          //筛选同id的不进行添加,对sketchSelect的id进行区分
          // data.element.forEach(sketchSelect => {
          //   if(sketchSelect.element && sketchSelect.element.id ){
          //     //通过产品的获取草图中控制点，未获取到控制点的不作为正确的翼型线进行处理
          //     wingTwistDesignCommand.getSplinePntsBySketch(sketchSelect.element.id,(sketchInfo)=>{
          //       let splinesPnts = sketchInfo.splinesPnts;
          //       if(splinesPnts.length !== 2){
          //         return;
          //       }
          //       //对获取的点进行处理，因翼型变更为上曲线+下曲线方式，为方便计算，在处理时仍采用合并为一条计算，生成时再拆为两条
          //       let pnts = [];
          //       for(let i = splinesPnts[0].length / 3 - 1;i > 0;i--) {
          //         pnts.push(new THREE.Vector3(splinesPnts[0][3 * i],splinesPnts[0][3 * i + 1],splinesPnts[0][3 * i + 2]));
          //       }
          //       for(let j = 0;j < splinesPnts[1].length / 3;j++) {
          //         pnts.push(new THREE.Vector3(splinesPnts[1][3 * j],splinesPnts[1][3 * j + 1],splinesPnts[1][3 * j + 2]));
          //       }
          //       console.log("2134141324234523523534534534534");
          //       console.log(pnts);
          //
          //       //获取草图的矩阵及根据矩阵获取对应的草图信息
          //       let sketchSelect = this.createSectionInfo(sketchInfo.sketchName, sketchInfo.matrix, pnts);
          //       this.params.sketches = [];
          //       this.params.sketches.push(sketchSelect);
          //     })
          //   }
          // })
        } else if (this.params.queryListActiveMap.datumPlane && data.element.length > 0) {
          let ele = data.element[0]?.element;
          if (ele) {
            this.params.datumPlane = [];
            this.params.datumPlane.push(ele);
            this.modifySectionInfo();
          }
        }
      })
    });

    //导入文件
    document.getElementById('file').addEventListener('change', e => {
      let files = e.target.files;
      let f = files[0];
      let reader = new FileReader();
      reader.onload = (e) => {
        let tempForm = [];
        // 判断是.txt或是.sldcrv
        if (f.type === 'text/plain' || f.name.endsWith(".sldcrv")) {
          tempForm = this.importTxt(e);
        }
        if ((tempForm.upCurvePoint.length % 3 === 0 && tempForm.downCurvePoint.length % 3 === 0) && (tempForm.upCurvePoint.length !== 0 && tempForm.downCurvePoint.length !== 0)) {
          //对获取的点进行处理，因翼型变更为上曲线+下曲线方式，为方便计算，在处理时仍采用合并为一条计算，生成时再拆为两条
          let pnts = [];
          for(let i = tempForm.upCurvePoint.length / 3 - 1;i > 0;i--) {
            pnts.push(new THREE.Vector3(parseFloat(tempForm.upCurvePoint[3 * i]),parseFloat(tempForm.upCurvePoint[3 * i + 1]),parseFloat(tempForm.upCurvePoint[3 * i + 2])));
          }
          for(let j = 0;j < tempForm.downCurvePoint.length / 3;j++) {
            pnts.push(new THREE.Vector3(parseFloat(tempForm.downCurvePoint[3 * j]),parseFloat(tempForm.downCurvePoint[3 * j + 1]),parseFloat(tempForm.downCurvePoint[3 * j + 2])));
          }

          //对旋转矩阵进行处理
          let matrix = [];
          for(let k = 0;k < tempForm.matrix.length;k++){
            matrix.push(parseFloat(tempForm.matrix[k]));
          }

          let sketchSelect = this.createSectionInfo(f.name, matrix, pnts);
          this.params.sketches = [];
          this.params.sketches.push(sketchSelect);
        } else {
          eventBus.emit('alert', 'message.CurveThroughXYZPointsCmd.importError', {
            type: 'warning',
            duration: 5
          });
        }
        document.getElementById('file').value = null;
      };
      reader.readAsBinaryString(f);
    });
  },

  methods: {
    changePluginContainerHeight() {
      wingTwistDesignCommand.changePluginContainerHeight({minWidth: this.$el.clientWidth, maxHeight: this.$el.clientHeight, width: 450});
    },
    focus(name) {
      this.originValue = this.params[name];
    },
    changeValue(name) {
      let element = document.getElementById(name);
      if (element) {
        let minValue = Number(element.min);
        let maxValue = Number(element.max);
        let value = this.params[name];
        if ((maxValue <= 0 && value < minValue) || (maxValue > 0 && (value < minValue || value > maxValue))) {
          this.params[name] = this.originValue;
        }
      }
    },
    confirmDisabled() {
      if (this.params.datumPlane.length === 0 || this.params.allSectionsInfo.length === 0) {
        return true;
      } else {
        return false;
      }
    },
    buttonDisabled() {
      if (this.params.allSectionsInfo.length === 0) {
        return true;
      } else {
        return false;
      }
    },
    //选中一行数据的时候执行
    handleCurrentChange(val) {
      this.selectRow = val;
      // this.setSectionInfo(val);
    },
    setSectionType() {
      this.params.sketches = [];
      if (this.sectionType === "1") {
        this.switchQuery("sketches");
      }
    },
    viewContent(scope) {
      let sketches = scope.row?.sketches;
      if (sketches?.length > 0) {
        let points = sketches[0]?.controlPnts;
        let strLinePoints = "";
        points?.forEach(point => {
          let x = (point.x * scope.row.zoomRatio).toFixed(4);
          let y = (point.y * scope.row.zoomRatio).toFixed(4);
          let z = (point.z * scope.row.zoomRatio).toFixed(4);
          let strPoint = x.toString() + " " + y.toString() + " " + z.toString();
          strLinePoints += "\n" + strPoint;
        })
        window.alert(strLinePoints);
      }
    },
    createSectionInfo(name, matrix, points) {
      let sectionMatrix = this.getSketchMatrix(matrix);
      let datumPlaneMatrix = this.getDatumPlaneMatrix();
      if (datumPlaneMatrix != null) {
        sectionMatrix = datumPlaneMatrix;
      }
      let sketchMathInfo = this.getSketchMathInfoByMatrix(sectionMatrix);
      let points3D = this.get3DPointBySketchPoint(points,sectionMatrix);

      let sectionInfo = {};
      sectionInfo.originPoints = points;
      sectionInfo.controlPnts = points3D;
      sectionInfo.sketchMathInfo = sketchMathInfo;
      sectionInfo.name = name;
      return sectionInfo;
    },
    getDatumPlaneMatrix() {
      if (this.params.datumPlane.length > 0) {
        let datum = this.params.datumPlane[0];
        let normal = datum.params.normal;
        let direction = datum.params.xDirection;
        let xDir = new THREE.Vector3(direction.x, direction.y, direction.z);
        let zDir = new THREE.Vector3(normal.x, normal.y, normal.z);
        let yDir = new THREE.Vector3().crossVectors(zDir, xDir);
        let origin = datum.params.origin;
        //获取三个方向
        let sectionMatrix = new THREE.Matrix4();
        sectionMatrix.makeBasis(xDir, yDir, zDir);
        sectionMatrix.setPosition(origin.x, origin.y, origin.z);
        return sectionMatrix;
      } else {
        return null;
      }
    },
    modifySectionInfo() {
      if (this.params.datumPlane.length > 0 && this.params.allSectionsInfo.length > 0) {
        let datumPlaneMatrix = this.getDatumPlaneMatrix();
        if (datumPlaneMatrix) {
          this.params.allSectionsInfo.forEach(sectionInfo => {
            if (sectionInfo.sketches.length > 0) {
              let sketch = sectionInfo.sketches[0];
              let sketchMathInfo = this.getSketchMathInfoByMatrix(datumPlaneMatrix);
              let points3D = this.get3DPointBySketchPoint(sketch.originPoints, datumPlaneMatrix);
              sketch.controlPnts = points3D;
              sketch.sketchMathInfo = sketchMathInfo;
            }
          })
        }
      }
    },
    confirm: function() {
      //预览的逻辑是根据现有的草图，对上次预览生成的草图以及引导线进行删除，再生成当下预览草图的引导线
      //确定的逻辑同预览，点击的时候关闭对话框
      //取消的逻辑是对上次预览生成的草图进行删除，关闭对话框

      this.preview(false, res => {
        this.close();
      });
    },

    close(){
      wingTwistDesignCommand.closeActiveCmd();
    },
    async preview(preview, cb) {
      //将当前页面的参数更新到当前组当中
      this.params.allSectionsInfo[this.params.index] = this.getSectionInfo();

      if (this.params.allSectionsInfo.length < 2) {
        return;
      }

      //如果截面多个截面位置中存在两组截面位置重合，返回错误
      let existedSectionPoss = [];
      for (let curSectionInfo of this.params.allSectionsInfo) {
        if (existedSectionPoss.indexOf(curSectionInfo.sectionPos) !== -1) {
          //同截面位置存在不同的翼型截面，返回错误
          return;
        } else {
          existedSectionPoss.push(curSectionInfo.sectionPos);
        }
      }

      //根据截面距离进行截面排序
      this.params.allSectionsInfo.sort(function (a, b) {
        return a.sectionPos - b.sectionPos;
      })

      //如果当前截面上没有翼型，使用上一个截面翼型

      //计算过程产生错误或者选取的模型计算中有错误，不应该进行预览，且应该删除现有预览内容
      let markError = false;
      //至少应该有第一个翼型草图存在，其他的截面中草图或者截面位置应该至少有一个
      this.params.allSectionsInfo.forEach(curSectionInfo => {
        if (curSectionInfo.index === 0) {
          //第一个截面应该有草图
          if (curSectionInfo.sketches.length === 0) {
            markError = true;
            return;
          }
        } else {
          //其他截面只要有翼型草图或者截面位置其中一个
          if (curSectionInfo.sketches.length === 0 && curSectionInfo.sectionPos === 0) {
            markError = true;
            return;
          }
        }
      })
      if (markError) {
        return;
      }

      //计算各截面的翼型曲线控制点
      await this.calculateSectionControlPnts();
      cb();
    },
    async calculateSectionControlPnts() {
      //根据机翼面积、展弦比、梢根比这三个属性计算机翼的水平投影形状
      //平均弦长
      //let averageChordLength = this.params.wingArea * 1000000 / this.wingSpan;
      //计算翼根弦长、翼尖弦长、翼展
      //let wingRootChordLength = 2 * averageChordLength / (1 + this.params.shootRootRatio);
      //let wingShootChordLength = wingRootChordLength * this.params.shootRootRatio;

      //所有截面翼型的点集
      let allSectionPnt = [];

      //机翼走向
      let rootWingProfileNormal = null;
      //翼根翼型的前缘点位置
      let rootWingProfileOrigin = null;
      //翼根翼型的弦长方向
      let rootWingProfileChordDir = null;
      //计算在不同截面位置的弦长应该是多少(距离为h时,l = a + (b - a) * h / H,其中l为梯形截线长度，a为下底长，b为上底长，h为l距a距离，H为b距a距离即梯形高)
      for (let i = 0; i < this.params.allSectionsInfo.length; i++) {
        let curSectionInfo = this.params.allSectionsInfo[i];

        //计算翼型截面的法向，即飞机机翼的走向，从翼根翼型获取，后续所有翼型应该平行于翼根翼型
        if (!rootWingProfileNormal && curSectionInfo.sketches.length > 0) {
          rootWingProfileNormal = curSectionInfo.sketches[0].sketchMathInfo.normal;

          rootWingProfileOrigin = this.getLeadingEdgePoint(curSectionInfo.sketches[0].controlPnts);
          if (!rootWingProfileNormal || !rootWingProfileOrigin) {
            return;
          }
          let rootWingProfilePnts = curSectionInfo.sketches[0].controlPnts;
          let rootWingProfileEnd = this.getTrailingEdgePoint(rootWingProfilePnts);
          rootWingProfileChordDir = (rootWingProfileEnd.clone().sub(rootWingProfileOrigin)).normalize();
        }
        //当前截面翼型采用的翼型的点集
        let sectionPnts = null;
        //当前翼面的法向
        let sectionWingProfileNormal = null;
        //如果选定了翼型，使用新的翼型点，如果没有选定，使用上一个存在的翼型作为当前截面的翼型
        if (curSectionInfo.sketches.length > 0) {
          sectionPnts = curSectionInfo.sketches[0].controlPnts;
          sectionWingProfileNormal = curSectionInfo.sketches[0].sketchMathInfo.normal;
        } else {
          for (let j = i - 1; j >= 0; j--) {
            if (this.params.allSectionsInfo[j].sketches.length > 0) {
              sectionPnts = this.params.allSectionsInfo[j].sketches[0].controlPnts;
              sectionWingProfileNormal = this.params.allSectionsInfo[j].sketches[0].sketchMathInfo.normal;
              break;
            }
          }
        }

        //当前选取翼型的弦长方向
        let sectionWingProfileOrigin = this.getLeadingEdgePoint(sectionPnts);
        let sectionWingProfileEnd = this.getTrailingEdgePoint(sectionPnts);
        let sectionWingProfileChordDir = (sectionWingProfileEnd.clone().sub(sectionWingProfileOrigin)).normalize();

        //当前截面翼型应该的弦长
        //let curSectionChordLength = wingRootChordLength + (wingShootChordLength - wingRootChordLength) * curSectionInfo.sectionPos / (this.wingSpan);
        let curSectionChordLength = (sectionWingProfileEnd.clone().sub(sectionWingProfileOrigin)).length() * curSectionInfo.zoomRatio;

        //通过翼根翼型的起点、法向、弦线方向，以及当前截面截面位置、弦线扭转角、弦长、后掠角、翼型所有点返回当前截面翼型的所有点坐标
        let curSectionWingProfilePnts = this.getSectionWingProfilePnts(rootWingProfileOrigin,
                rootWingProfileNormal,
                rootWingProfileChordDir,
                sectionWingProfileOrigin,
                sectionWingProfileNormal,
                sectionWingProfileChordDir,
                curSectionInfo.sectionPos,
                parseFloat(curSectionInfo.torsionAngle),
                curSectionChordLength,
                parseFloat(this.params.backSweepAngle),
                sectionPnts);

        //对于飞机的左右机翼，其翼展方向是相反的，因此需要关于翼根翼型截面对称
        if (this.sideValue === "1") {
          for (let i = 0; i < curSectionWingProfilePnts.length; i++) {
            curSectionWingProfilePnts[i] = this.getSymmetryPnt(rootWingProfileNormal, rootWingProfileOrigin, curSectionWingProfilePnts[i]);
          }
        }

        //产品2024R2时支持样条曲线起始终止点设置切线方向，R3后不支持，此处是在进行闭合样条曲线时首尾同一个点处理用。
        //curSectionWingProfilePnts.push(this.getTrailingEdgePoint(curSectionWingProfilePnts));

        let allOriginPnts = [];
        sectionPnts.forEach(pnt => {
          allOriginPnts.push(new THREE.Vector3(pnt.x, pnt.y, pnt.z));
        })

        allSectionPnt.push(curSectionWingProfilePnts);
      }

      //绘制多条引导线
      this.guideLinesInfo = [];
      //引导线暂时使用两条，一条是初始点组成的引导线，一条是草图原点组成的引导线
      let guideLine1Pt = [];
      let guideLine2Pt = [];
      allSectionPnt.forEach(sketchInfo => {
        guideLine1Pt.push(sketchInfo[0]);
        guideLine2Pt.push(this.getLeadingEdgePoint(sketchInfo));
      })
      //在进行多条引导线绘制时，可能会出现拓扑逻辑计算错误，使用一条引导线即可
      this.guideLinesInfo.push(guideLine1Pt);
      //this.guideLinesInfo.push(guideLine2Pt);

      let params = {
        sketchesInfo: allSectionPnt,           //已经进行完旋转的点，第一个草图不参与旋转
        guideLinesInfo: this.guideLinesInfo,       //绘制放样曲面的引导线，多条引导线，每条引导线有多个点
        markCalculate: true,                 //是否进行重新生成，false时不进行重新生成并且清除上一预览
        preview: false,
      }
      console.log(params);
      //调用产品内核接口进行草图放样
      await wingTwistDesignCommand.createWingTwistBySection(params);
    },
    //选中的item
    selectItem(index,Item){
      this.selectedItem = Item;
      this.selectedItem.index = index;
    },
    //通过翼根翼型的起点、法向，以及当前截面弦线方向、截面位置、弦线扭转角、弦长、后掠角、翼型所有点返回当前截面翼型的所有点坐标
    getSectionWingProfilePnts(rootOrigin,
                              rootNormal,
                              rootChordDir,
                              sectionOrigin,
                              sectionNormal,
                              templateChordDir,
                              sectionPos,
                              sectionTorsionAngle,
                              sectionChordLength,
                              sectionBackSweepAngle,
                              sectionWingProfilePnts){
      //1.根据翼根翼型的起点和后掠角计算当前翼型的起点
      //旋转轴方向
      let revolveAxisDir = new THREE.Vector3().crossVectors(templateChordDir,rootNormal);
      revolveAxisDir.normalize();

      //上一翼型起点到当前翼型起点的方向
      let dirOrigin1ToOrigin2 = (this.getLineRevolveDir(revolveAxisDir,rootOrigin,rootNormal,-sectionBackSweepAngle)).normalize();

      //当前翼型起点坐标 = 上一起点 + 偏移方向 * 偏移距离 / 后掠角的余弦值
      let sectionOriginPnt = rootOrigin.clone().add(dirOrigin1ToOrigin2.clone().multiplyScalar(sectionPos / Math.cos(sectionBackSweepAngle * Math.PI / 180)));

      //2.通过旋转角获取当前翼型弦线的方向
      let sectionChordDir = this.getLineRevolveDir(rootNormal,sectionOriginPnt,rootChordDir,sectionTorsionAngle);

      //3.获取弦长比例，作为缩放比例
      //原翼型模板弦长
      let templateChordLength = (this.getTrailingEdgePoint(sectionWingProfilePnts).clone().sub(this.getLeadingEdgePoint(sectionWingProfilePnts))).length();
      let zoomScale = sectionChordLength / templateChordLength;

      //4.整体截面翼型进行旋转平移及缩放到对应位置
      //根据起始坐标系的原点、XY轴向以及目标坐标系的原点、XY轴向及缩放比例获取变换矩阵
      let transformMatrix = this.getTransformMatrix(sectionOrigin,templateChordDir,sectionNormal,sectionOriginPnt,sectionChordDir,rootNormal,zoomScale);

      //5.根据获取到的矩阵将模板中的翼型变换到截面位置
      let newWingProfilePnts = [];
      sectionWingProfilePnts.forEach(profilePnt => {
        newWingProfilePnts.push(profilePnt.clone().applyMatrix4(transformMatrix));
        //test
        // let newPoint = new THREE.Vector3(profilePnt.clone().applyMatrix4(transformMatrix).x,
        //   profilePnt.clone().applyMatrix4(transformMatrix).y + 1000,
        //   profilePnt.clone().applyMatrix4(transformMatrix).z);
        // newWingProfilePnts.push(newPoint);
      })
      return newWingProfilePnts;
    },
    //根据两个坐标轴系的原点及轴向获取变换矩阵,并进行缩放
    getTransformMatrix(startOrigin,startXDir,startYDir,endOrigin,endXDir,endYDir,scale){
      let startMatrix = new THREE.Matrix4();
      startMatrix.makeBasis(startXDir,startYDir,new THREE.Vector3().crossVectors(startXDir,startYDir));
      startMatrix.setPosition(startOrigin.x,startOrigin.y,startOrigin.z);

      let endMatrix = new THREE.Matrix4();
      endMatrix.makeBasis(endXDir,endYDir,new THREE.Vector3().crossVectors(endXDir,endYDir));
      endMatrix.setPosition(endOrigin.x,endOrigin.y,endOrigin.z);

      let transformMatrix = new THREE.Matrix4();
      transformMatrix.makeScale(scale,scale,scale);
      //transformMatrix.copy(endMatrix).multiply(startMatrix.invert());
      // let transformMoveAndRotate = endMatrix.clone().multiply(startMatrix.clone().invert());
      // let trans1 = transformMoveAndRotate.clone().multiply(transformMatrix);
      // let trans2 = transformMatrix.clone().multiply(transformMoveAndRotate);
      //矩阵应该是当前坐标系先变换到全局坐标系，进行缩放，再变换到新的坐标系中
      let trans = endMatrix.clone().multiply(transformMatrix).multiply(startMatrix.clone().invert());
      //let trans = transformMatrix.multiply(startMatrix.clone().invert());
      //let trans = startMatrix.clone().invert();
      return trans;
    },
    //当前激活的选取框切换
    switchQuery(name) {
      for (const key in this.params.queryListActiveMap) {
        if (key === name){
          this.params.queryListActiveMap[key] = 1;
          if(this.params.key){
            let ids = this.params[key].map(ele => ele.id);
            if (ids) {
              //wingTwistDesignCommand.highLightElement(ids);
            }
          }
        }else{
          this.params.queryListActiveMap[key] = 0;
        }
      }
      if (name === "datumPlane") {
        wingTwistDesignCommand.setSelectType([ElementType.DATUMPLANE]);
      } else if (name === "sketches") {
        wingTwistDesignCommand.setSelectType([ElementType.SKETCHREGION, ElementType.FACE]);
      }
    },
    //将字符串转为4*4矩阵
    getSketchMatrix(mat){
      let matrix = new THREE.Matrix4();
      matrix.set(
        mat[0], mat[4], mat[8], mat[12],
        mat[1], mat[5], mat[9], mat[13],
        mat[2], mat[6], mat[10], mat[14],
        mat[3], mat[7], mat[11], mat[15]
      );
      return matrix;
    },
    //通过矩阵获取草图原点和法向
    getSketchMathInfoByMatrix(matrix){
      //通过矩阵获取草图原点
      let originPoint = new THREE.Vector3().setFromMatrixPosition(matrix);
      //通过矩阵获取草图的U、V、normal方向
      let diru = new THREE.Vector3().setFromMatrixColumn(matrix, 0);
      let dirv = new THREE.Vector3().setFromMatrixColumn(matrix, 1);
      let dir = new THREE.Vector3().setFromMatrixColumn(matrix, 2);
      dir.normalize();
      // let cosAlpha = originPoint.multiply(dir) / (originPoint.length() * dir.length());
      // if(cosAlpha < 0){
      //   dir = -dir;
      // }

      //通过草图的信息定义草图平面
      let plane = new THREE.Plane(dir,originPoint.length());
      let sketchMatrixInfo = {
        origin:originPoint,
        normal:dir,
        u:diru,
        v:dirv,
        plane:plane,
        matrix:matrix,
      }
      return sketchMatrixInfo;
    },
    //方向绕直线进行旋转得到的方向
    getLineRevolveDir(lineDir,linePoint,dir,angle){
      let revolvePoint = this.getLineRevolvePoint(lineDir,linePoint,linePoint.clone().add(dir),angle);
      return revolvePoint.clone().sub(linePoint);
    },
    //获取平面对称的点，通过平面的法向、平面上一点、需要对称的点，返回对称点
    getSymmetryPnt(planeNormal,planePnt,point){
      //获取点在平面上的投影坐标
      let projectPnt = point.clone().sub(planeNormal.clone().multiplyScalar((point.clone().sub(planePnt)).dot(planeNormal)));

      return projectPnt.clone().add(projectPnt.clone().sub(point));
    },
    //点绕直线进行旋转得到的返回点
    getLineRevolvePoint(lineDir,linePoint,point,angle){
      //角度转换为弧度
      angle = angle * Math.PI / 180;

      //根据轴和角度设计旋转矩阵
      let rotateMatrix = new THREE.Matrix4();
      rotateMatrix.makeRotationAxis(lineDir,angle);

      //将旋转点进行位移到原点为基准的位置
      let directionToPoint = new THREE.Vector3().subVectors(point,linePoint);
      //应用旋转矩阵进行旋转
      directionToPoint.applyMatrix4(rotateMatrix);

      //旋转后的点加上基准
      let rotatedPoint = directionToPoint.add(linePoint);
      return rotatedPoint;
    },
    //定义规则，如何获取一组点中的前缘和后缘
    //现有前缘获取规则：获取原点位置，认为一组翼型控制点中的中间位置的点作为翼型的原点
    getLeadingEdgePoint(points){
      let pointsLength = points.length;
      //长度为偶数取中间偏后一个为起始点，为奇数取中间点为起始点
      if(pointsLength % 2 === 0){
        return points[pointsLength / 2];
      }else{
        return points[(pointsLength - 1) / 2];
      }
    },
    //现有后缘获取规则:认为一组点中的第一个点就是后缘点
    getTrailingEdgePoint(points){
      return points[0];
    },
    //新增截面数据
    addSectionData() {
      let curSectionPos = parseFloat(this.wingSpan);
      this.params.index = this.params.allSectionsInfo.length;
      this.params.name = (this.params.allSectionsInfo.length + 1).toString();
      this.params.sectionPos = curSectionPos;
      this.sectionType = "0";
      this.params.zoomRatio = 1;
      this.params.torsionAngle = 0;
      this.params.sketches = [];
      this.isEdit = true;
    },
    //编辑
    editSectionData() {
      if (!this.selectRow) {
        return;
      }
      this.setSectionInfo(this.selectRow);
      this.isEdit = true;
    },
    deleteSectionData() {
      //必须保证有一个截面数据
      if(this.params.allSectionsInfo.length <= 0) {
        return;
      }
      let newGroups = [];
      this.params.allSectionsInfo.forEach(group =>{
        if(group.index < this.params.index){
          newGroups.push(group);
        }else if(group.index > this.params.index){
          group.index -= 1;
          group.name = (group.index + 1).toString();
          newGroups.push(group);
        }
      })
      this.params.allSectionsInfo = newGroups;
      //当删除非第一个时，向前一个为当前显示，如果是第一个，则第一个为当前显示
      if(this.params.index !== 0){
        this.setSectionInfo(this.params.allSectionsInfo[this.params.index - 1]);
      }else{
        this.setSectionInfo(this.params.allSectionsInfo[0]);
      }
    },
    saveSectionData() {
      if (this.params.sketches.length <= 0) {
        wingTwistDesignCommand.eventBusAlertMsg("请选择或导入截面数据！", "warning");
        return;
      }
      //判断是否是新建还是编辑
      let isAdd = true;
      for(let i = 0;i < this.params.allSectionsInfo.length;i++){
        if(this.params.allSectionsInfo[i].index === this.params.index){
          this.params.allSectionsInfo[i].sectionPos = this.params.sectionPos;
          this.params.allSectionsInfo[i].sectionType = this.sectionType;
          this.params.allSectionsInfo[i].zoomRatio = this.params.zoomRatio;
          this.params.allSectionsInfo[i].torsionAngle = this.params.torsionAngle;
          this.params.allSectionsInfo[i].sketches = this.params.sketches;
          //刷新列表
          isAdd = false;
          break;
        }
      }
      if (isAdd) {
        let sectionInfo = {
          index: this.params.index,
          name: this.params.name,
          sketches: this.params.sketches,
          sectionPos: this.params.sectionPos,          //当前截面位置
          sectionType: this.sectionType,
          zoomRatio: this.params.zoomRatio,                       //当前截面缩放比
          torsionAngle: this.params.torsionAngle,                    //当前截面扭转角
        }
        this.params.allSectionsInfo.push(sectionInfo);
      }
      this.isEdit = false;
    },
    //更新组
    updateGroup(btnType) {
      //将当前内容保存到对应的当前组中
      for(let i = 0;i < this.params.allSectionsInfo.length;i++){
        if(this.params.allSectionsInfo[i].index === this.params.index){
          this.params.allSectionsInfo[i] = this.getSectionInfo();
          break;
        }
      }

      //next 或者 last 应该将当前显示内容切换为next或last
      let newGroups = [];
      if(btnType === "del"){
        //删除时，先进行数量判断(当只有一组时，无法再进行删除)，然后进行group中所有大于当前的index都减1
        if(this.params.allSectionsInfo.length > 1){
          this.params.allSectionsInfo.forEach(group =>{
            if(group.index < this.params.index){
              newGroups.push(group);
            }else if(group.index > this.params.index){
              group.index -= 1;
              group.name = (group.index + 1).toString();
              newGroups.push(group);
            }
          })
          this.params.allSectionsInfo = newGroups;
          //当删除非第一个时，向前一个为当前显示，如果是第一个，则第一个为当前显示
          if(this.params.index !== 0){
            this.setSectionInfo(this.params.allSectionsInfo[this.params.index - 1]);
          }else{
            this.setSectionInfo(this.params.allSectionsInfo[0]);
          }
        }
      }else if(btnType === "add"){
        let curSectionPos = parseFloat(this.wingSpan);
        //添加时，将新的数据先保存到数组中
        let sectionInfo = {
          index:this.params.allSectionsInfo.length,
          name:(this.params.allSectionsInfo.length + 1).toString(),
          sketches:[],
          sectionPos: curSectionPos,          //当前截面位置
          zoomRatio: 1,                       //当前截面缩放比
          torsionAngle: 0,                    //当前截面扭转角
        }
        this.setSectionInfo(sectionInfo);
        this.params.allSectionsInfo.push(sectionInfo);
      }else if(btnType === "next"){
        if(this.params.index === this.params.allSectionsInfo.length - 1){
          this.setSectionInfo(this.params.allSectionsInfo[0]);
        }else{
          this.setSectionInfo(this.params.allSectionsInfo[this.params.index + 1]);
        }
      }else if(btnType === "last"){
        if(this.params.index === 0){
          this.setSectionInfo(this.params.allSectionsInfo[this.params.allSectionsInfo.length - 1]);
        }else{
          this.setSectionInfo(this.params.allSectionsInfo[this.params.index - 1]);
        }
      }

      //限定当前截面位置调整范围为上一个截面位置和下一个截面位置之间,第一个截面位置只能是0，最后一个截面位置是翼展长度/2
      if(this.params.index === 0){
        this.sectionPosMin = 0;
        this.sectionPosMax = 0;
      }else if(this.params.index === this.params.allSectionsInfo.length - 1){
        this.sectionPosMin = this.wingSpan;
        this.sectionPosMax = this.wingSpan;
        this.params.sectionPos = this.wingSpan;
      }else{
        this.sectionPosMin = this.params.allSectionsInfo[this.params.index - 1].sectionPos;
        this.sectionPosMax = this.params.allSectionsInfo[this.params.index + 1].sectionPos;
      }
    },
    updateGroup2(group) {
      //将当前内容保存到对应的当前组中
      for(let i = 0;i < this.params.allSectionsInfo.length;i++){
        if(this.params.allSectionsInfo[i].index === this.params.index){
          this.params.allSectionsInfo[i] = this.getSectionInfo();
          break;
        }
      }
      this.setSectionInfo(group);
    },
    //更新截面位置的范围
    refreshSectionPos(){
      //根据机翼面积、展弦比、梢根比这三个属性计算机翼的水平投影形状
      //平均弦长
      let wingSpanLength = Math.sqrt(this.params.wingArea * 1000000 * this.params.aspectRatio);

      //最远的翼型截面距离也不应该超过翼展/2
      //this.sectionPosMax = wingSpanLength / 2;
      this.wingSpan = wingSpanLength / 2;
    },
    get3DPointBySketchPoint(listPntOrigin,matrix){
      let listPnt3D = [];
      listPntOrigin.forEach(pointOrigin => {
        let point = new THREE.Vector3(pointOrigin.x,pointOrigin.y,pointOrigin.z);
        let pnt3D = point.clone().applyMatrix4(matrix);
        listPnt3D.push(pnt3D);
      })
      return listPnt3D;
    },
    setSectionInfo(sectionInfo){
      this.params.index = sectionInfo.index;
      this.params.name = sectionInfo.name;
      this.params.sectionPos = sectionInfo.sectionPos;
      this.sectionType = sectionInfo.sectionType;
      this.params.zoomRatio = sectionInfo.zoomRatio;
      this.params.torsionAngle = sectionInfo.torsionAngle;
      this.params.sketches = sectionInfo.sketches;
    },
    getSectionInfo(){
      let sectionInfo = {
        index:this.params.index,
        name:this.params.name,
        sectionPos:this.params.sectionPos,
        sectionType:this.params.sectionType,
        zoomRatio:this.params.zoomRatio,
        torsionAngle:this.params.torsionAngle,
        sketches:this.params.sketches,
      }
      return sectionInfo;
    },
    selectFile() {
      document.getElementById('file').click();
    },
    importTxt(e) {
      let data = e.target.result;
      let dataLine;

      data = data.replace(/\0/g, "");
      data = data.replace(/\n/g, ",");
      data = data.split(",");
      dataLine = data[0].replace(/\s+/g, ",");
      dataLine = dataLine.split(",");

      let curveType = -1;  //上下曲线，矩阵0，上曲线1，下曲线2
      let TempForm = {
        matrix:[],
        upCurvePoint:[],
        downCurvePoint:[]
      };
      for (let i = 0; i < data.length; i++) {
        //如果获取的当前行为Up Curve:或者Down Curve:时，作为上下曲线的标志位
        if(data[i] === "Matrix:"){
          curveType = 0;
          continue;
        }else if(data[i] === "Up Curve:"){
          curveType = 1;
          continue;
        }else if(data[i] === "Down Curve:"){
          curveType = 2;
          continue;
        }
        if(curveType === -1){
          continue;
        }

        let line = data[i].replace(/\s+/g, ",");
        line = line.split(",");
        let lines = this.pickNumInLine(line);
        if (lines.length === 0) {
          continue;
        }

        if(curveType === 0){
          TempForm.matrix.push(...lines);
        }else if(curveType === 1){
          TempForm.upCurvePoint.push(...lines);
        }else if(curveType === 2){
          TempForm.downCurvePoint.push(...lines);
        }
      }
      return TempForm;
    },
    pickNumInLine(line) {
      let lines = [];
      let reg = /^-?\d+\.?\d*$/;
      for (let num = 0; num < line.length; num++) {
        let checkLineValue = line[num];
        if (checkLineValue !== "") {
          if (!checkLineValue && checkLineValue !== 0) {
            // 用于后续判断不符合要求弹出提示
            lines.length = 0;
            lines.push("a");
            return lines;
          }
          if (reg.test(checkLineValue)) {
            checkLineValue = eval(checkLineValue);
            if (!checkLineValue && checkLineValue !== 0) continue;
            checkLineValue = checkLineValue.toString();
            checkLineValue = checkLineValue.replace(/[^-0123456789]/g, ".");
            checkLineValue = checkLineValue.split(/[^-.0123456789]/g);
            let jointValues = "";
            checkLineValue.forEach(le => {
              if (le !== "") {
                if (checkLineValue.length >= 3) {
                  jointValues += le;
                } else if (checkLineValue.length === 1) {
                  jointValues = le;
                } else {
                  lines = [];
                  return lines;
                }
              }
            });
            if (!!jointValues) {
              lines.push(jointValues);
            } else{
              if(lines.length === 0){
                return lines;
              }
              lines.length = 0;
              lines.push("a");
              return lines;
            }
          } else {
            lines.length = 0;
            lines.push("a");
            return lines;
          }
        } else if (num >= 3 && checkLineValue !== "" ) {
          lines.length = 0;
          lines.push("a");
          return lines;
        } else {
          line.splice(num, 1);
        }
      }
      return lines;
    },
  },

  watch: {
  },
};
</script>
<style scoped>
.wrap {
    font-size: 12px;
}
.query-description {
    line-height: 24px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 12px;
    transition: .3s;
}
.move-buttons {
    margin-right: 35px;
}
.description-enlarge {
    font-size: inherit;
}
/*.label {*/
/*    max-width: 100px;*/
/*    overflow: hidden;*/
/*    text-overflow: ellipsis;*/
/*}*/
.result-list {
    padding: 2px 10px;
    max-height: 180px;
    overflow-y: auto;
}

.result-item {
    margin: 1px 0;
    padding: 2px 0 2px 4px;
    display: flex;
    align-items: center;
}

.result-item .angle-icon {
    font-weight: bold;
    padding: 0 2px;
}

.result-item-title {
    flex-grow: 1;
}

.ident {
    padding-left: 14px;
}

.selected-query-li {
    border-radius: 3px;
    background-color: var(--bg-color3);
}
.dialog-query-list .move-buttons {
    margin-right: 35px;
}
.group {
    display: flex;
    justify-content: center;
}
.group-btn:hover {
    background-color: var(--bg-color8);
    cursor: pointer;
}
.group-btn {
    width: 24px;
    height: 24px;
    border: var(--bg-color8) 1px solid;
    border-radius: 3px;
    font-size: 16px;
    text-align: center;
    display: flex;
    justify-content: center;
    align-items: center;
    margin: 2px;
}
.group-text {
    margin: 0 5px;
}
.group-btn:active {
    box-shadow: 2px 2px #999 inset;
}
.radio >>> .el-radio__label {
    padding-left: 2px;
}
.curve-button {
    padding-left: 10px;
}

.groups-box {
  height: 100px;
  overflow-y: auto;
}

.group-item {
  padding: 5px 2px;
  margin-left: 2px;
  margin-right: 2px;
  margin-bottom: 1px;
  border-bottom: solid1 1px var(--border-color3);
}

.group-item:hover {
  background-color: var(--bg-color3);
}

.selected-group {
  background-color: var(--bg-color4);
}

.collapse-panel > .collapse-a {
  color: var(--text-color1);
  margin: 5px 0;
}

.collapse-a {
  display: flex;
  justify-content: space-between;
}

.font-color {
  color: #606266;
}

.operation-border {
  border: 2px solid var(--bg-color3);
  padding: 8px;
}

.button-style {
  display: flex;
  justify-content: flex-end;
  margin-top: 5px;
}

.label-style {
  font-size: 12px;
  color: #606266;
  line-height: 30px;
}
</style>
